﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Reflection;

namespace AudioPlayer.Plugin {
	/// <summary>
	/// Plugin base class
	/// </summary>
	internal class PluginBase : IPluginBase{
		#region Fields
		private AppDomain _domain;
		private Assembly _asm;
		private Type _type;
		private IPlugin _plugin;

		private bool _autoLoad;
		private int _totalLoad;
		private int _totalFail;
		#endregion
		#region Constructor
		/// <summary>
		/// Initializes a new instance of the <see cref="PluginBase"/> class.
		/// </summary>
		/// <param name="type">The type.</param>
		public PluginBase(Type type) {
			_type = type;
		}
		public PluginBase(IPlugin plugin) {
			_plugin = plugin;
			_type = plugin.GetType();
		}
		#endregion
		#region Public Voids
		/// <summary>
		/// Loads plugin
		/// </summary>
		public void Load() {
			//Just to be sure
			Config.Plugins.Load(this);
		}

		/// <summary>
		/// Unloads plugin.
		/// </summary>
		public void Unload() {
			//Check if it's loaded
			if (this.Loaded) {
				//Dispose, and set to null
				_plugin.Dispose();
				_plugin = null;
			}
		}
		#endregion
		#region Property
		/// <summary>
		/// Gets or sets the domain.
		/// </summary>
		/// <value>The domain.</value>
		public AppDomain Domain {
			get {
				return _domain;
			}
			set { _domain = value; }
		}
		/// <summary>
		/// Gets or sets the assembly.
		/// </summary>
		/// <value>The assembly.</value>
		public Assembly Assembly {
			get { return _asm; }
			set { _asm = value; }
		}
		/// <summary>
		/// Gets or sets the type.
		/// </summary>
		/// <value>The type.</value>
		public Type Type {
			get { return _type; }
			set { _type = value; }
		}
		/// <summary>
		/// Guid for tracking plugins
		/// </summary>
		/// <value></value>
		public Guid Guid {
			get {
				if (_type != null) {
					return _type.GUID;
				} else {
					return Guid.Empty;
				}
			}
		}

		/// <summary>
		/// Gets the plugin.
		/// </summary>
		/// <value>The plugin.</value>
		public IPlugin Plugin {
			get {
				return _plugin;
			}
			set {
				_plugin = value;
			}
		}

		/// <summary>
		/// Gets a value indicating whether this plugin is loaded, and ready to use
		/// </summary>
		/// <value><c>true</c> if loaded; otherwise, <c>false</c>.</value>
		public bool Loaded {
			get {
				if (_plugin != null) {
					return true;
				} else {
					return false;
				}
			}
		}

		/// <summary>
		/// Gets or sets a value indicating whether this plugin should automaticaly lad.
		/// </summary>
		/// <value><c>true</c> if loads automaticaly; otherwise, <c>false</c>.</value>
		public bool AutoLoad {
			get { return _autoLoad; }
			set { _autoLoad = value; }
		}
		/// <summary>
		/// Gets the total load.
		/// </summary>
		/// <value>The total load.</value>
		public int TotalLoad {
			get { return _totalLoad; }
			set { _totalLoad = value; }
		}
		/// <summary>
		/// Gets the total fail.
		/// </summary>
		/// <value>The total fail.</value>
		public int TotalFail {
			get { return _totalFail; }
			set { _totalFail = value; }
		}

		/// <summary>
		/// Gets a value indicating whether this <see cref="PluginBase"/> is ready to load.
		/// </summary>
		/// <value><c>true</c> if ready; otherwise, <c>false</c>.</value>
		public bool Ready {
			get {
				if (_asm != null && _domain != null) {
					return true;
				}
				return false;
			}
		}
		#endregion
	}

	/// <summary>
	/// Generic base plugin class
	/// </summary>
	/// <typeparam name="TPlugin">The type of the plugin.</typeparam>
	internal class PluginBase<TPlugin> : IPluginBase<TPlugin> {
		#region Fields
		private PluginBase _base;
		#endregion
		#region Constructor
		public PluginBase(Type type) {
			_base = new PluginBase(type);
		}
		public PluginBase(IPlugin plugin) {
			_base = new PluginBase(plugin);
		}
		public PluginBase(PluginBase basePlugin) {
			_base = basePlugin;
		}
		#endregion
		#region Static
		public static explicit operator PluginBase(PluginBase<TPlugin> plugin) {
			return plugin._base;
		}
		public static implicit operator PluginBase<TPlugin>(PluginBase plugin) {
			return new PluginBase<TPlugin>(plugin);
		}
		#endregion
		#region Public Voids

		/// <summary>
		/// Loads plugin
		/// </summary>
		public void Load() {
			_base.Load();
		}

		/// <summary>
		/// Unloads plugin.
		/// </summary>
		public void Unload() {
			_base.Unload();
		}
		#endregion
		#region Property
		/// <summary>
		/// Gets a value indicating whether this plugin is loaded, and ready to use
		/// </summary>
		/// <value><c>true</c> if loaded; otherwise, <c>false</c>.</value>
		public bool Loaded {
			get { return _base.Loaded; }
		}
		/// <summary>
		/// Gets the total load.
		/// </summary>
		/// <value>The total load.</value>
		public int TotalLoad { get { return _base.TotalLoad; } set { _base.TotalLoad = value; } }
		/// <summary>
		/// Gets the total fail.
		/// </summary>
		/// <value>The total fail.</value>
		public int TotalFail { get { return _base.TotalFail; } set { _base.TotalFail = value; } }
		/// <summary>
		/// Gets or sets a value indicating whether this plugin should automaticaly lad.
		/// </summary>
		/// <value><c>true</c> if loads automaticaly; otherwise, <c>false</c>.</value>
		public bool AutoLoad { get { return _base.AutoLoad; } set { _base.AutoLoad = value; } }
		/// <summary>
		/// Gets the plugin.
		/// </summary>
		/// <value>The plugin.</value>
		public TPlugin Plugin {
			get { return (TPlugin)_base.Plugin; }
			set { _base.Plugin = (IPlugin)value; }
		}
		/// <summary>
		/// Gets the plugin.
		/// </summary>
		/// <value>The plugin.</value>
		IPlugin IPluginBase.Plugin {
			get { return _base.Plugin; }
		}

		#endregion
	}
}
